package jtacck.labmedicine;

import jvm.jtacck.serials.LoginInfo;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.DialogInterface.OnCancelListener;
import android.content.SharedPreferences;
import android.location.Location;
import android.location.LocationManager;
import android.os.AsyncTask;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.EditText;
import android.widget.Toast;

/**
 * @author Andrew Lau
 * 
 *         Event handler for the 'submit' button on the login screen
 */
public class LoginButton implements OnClickListener {

    /**
     * Handler to the main activity
     */
    private static Activity main;

    /**
     * Text username and password entered in the text box
     */
    private static EditText username, password;

    private static SharedPreferences pref;

    /**
     * Reference to AsyncTask
     */
    private static Login temp = new Login();

    /**
     * Thread used for timeout of logging in.
     */
    private static Thread t;

    /**
     * @param main
     *            Reference to the main activity
     * @param username
     *            Username entered in the text box
     * @param password
     *            Password entered in the text box
     */
    protected LoginButton(Activity main, EditText username, EditText password) {
        LoginButton.main = main;
        LoginButton.username = username;
        LoginButton.password = password;
        pref = PreferenceManager.getDefaultSharedPreferences(main);
    }

    /*
     * (non-Javadoc)
     * 
     * @see android.view.View.OnClickListener#onClick(android.view.View)
     * 
     * Event handler when the button is clicked, creates an AsyncTask that
     * connects to the Android server in the background. Runs a thread that will
     * cancel the AsyncTask in 10 seconds as a time out functionality
     */
    public void onClick(View arg0) {

        // make sure the task isn't about to run or pending
        if (temp.getStatus() != AsyncTask.Status.PENDING
                || temp.getStatus() != AsyncTask.Status.RUNNING) {
            temp = new Login();
            temp.execute();

            // we need to set a timeout incase login takes too long
            // work in progress
            t = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        // Retrieve the value that we set in our preferences
                        Thread.sleep(Integer.parseInt(pref.getString(main
                                .getString(R.string.preferences_timeout_key),
                                "")) * 1000);
                        if (MainActivity.linker != null) {
                            temp.cancel(true);
                        }
                    } catch (InterruptedException e) {
                        Log.i("LoginButton",
                                "Timeout thread has been interrupted");
                    }
                }
            });
            t.start();
        }
    }

    /**
     * @author Andrew Lau
     * 
     *         AsyncTask that handles login for the Android
     * 
     */
    static class Login extends AsyncTask<Void, Integer, Integer> {
        private ProgressDialog pd;

        /*
         * (non-Javadoc)
         * 
         * @see android.os.AsyncTask#onPreExecute()
         * 
         * Pops up a progress dialog on the main activity, blocking user from
         * entering any input until the AsyncTask is done executing
         */
        @Override
        protected void onPreExecute() {
            pd = ProgressDialog.show(main, "",
                    "Attempting to log in to server...", true, true,
                    new OnCancelListener() {

                        /*
                         * (non-Javadoc)
                         * 
                         * @see
                         * android.content.DialogInterface.OnCancelListener#
                         * onCancel(android.content.DialogInterface)
                         * 
                         * Interrupt our timeout thread and disconnect if a user
                         * cancels our dialog
                         */
                        @Override
                        public void onCancel(DialogInterface dialog) {
                            t.interrupt();
                            LoginButton.temp.cancel(true);
                            if (MainActivity.linker != null) {
                                MainActivity.linker.disconnect();
                            }
                        }
                    });
        }

        /*
         * (non-Javadoc)
         * 
         * @see android.os.AsyncTask#doInBackground(Params[])
         * 
         * Background execution of the AsyncTask. Starts by creating a
         * ServerLinker object and then attempts to establish connection and
         * authentication with the Android server.
         */
        @Override
        protected Integer doInBackground(Void... params) {

            // Create new login information
            LoginInfo info = new LoginInfo(username.getText().toString(),
                    password.getText().toString());

            // This is repeated throughout the code since you need to check if
            // the task has been canceled
            if (isCancelled()) {
                return 3;
            }

            // Read values from our preference
            MainActivity.linker = new ServerLinker(
                    pref.getString(
                            main.getString(R.string.preferences_host_key), ""),
                    Integer.parseInt(pref.getString(
                            main.getString(R.string.preferences_listenport_key),
                            "")), Integer.parseInt(pref.getString(main
                            .getString(R.string.preferences_requestport_key),
                            "")), info);
            if (isCancelled()) {
                return 3;
            }
            // Authenticate with the server
            MainActivity.linker.authenticate();
            if (isCancelled()) {
                return 3;
            }

            // Check to make sure linker is connected
            if (!MainActivity.linker.connect()) {
                if (isCancelled()) {
                    return 3;
                }
                return 1;
            }

            // Check to make sure it stil lis authenticated
            if (!MainActivity.linker.authenticated()) {
                if (isCancelled()) {
                    return 3;
                }
                if (MainActivity.linker.loggedIn()) {
                    return 4;
                } else {
                    return 2;
                }
            }

            if (isCancelled()) {
                return 3;
            }
            MainActivity.linker.startListening();
            ServerLinker linker = MainActivity.linker;

            if (isCancelled()) {
                return 3;
            }
            // Retrieve the check list data
            MainActivity.routeCheckList = linker.getCheckListPair();
            MainActivity.cache.setStartEndChecklists(MainActivity.routeCheckList);
            MainActivity.route = linker.getNextRoute();
            return 0;
        }

        /*
         * (non-Javadoc)
         * 
         * @see android.os.AsyncTask#onCancelled()
         * 
         * Handler for when the AsyncTask is canceled. Interrupts timeout thread
         * and tells users they canceled or timed out
         */
        @Override
        protected void onCancelled() {
            t.interrupt();
            pd.dismiss();
            Toast.makeText(main.getApplicationContext(),
                    "Login canceled or timed out.", Toast.LENGTH_LONG).show();
            if (MainActivity.linker != null) {
                MainActivity.linker.disconnect();
            }
        }

        /*
         * (non-Javadoc)
         * 
         * @see android.os.AsyncTask#onPostExecute(java.lang.Object)
         * 
         * Handler for when the AsyncTask finishes its background execution.
         * Displays different behavior on the UI base on what happened in the
         * execution handler. Starts the route screen activity when the user
         * establishes a connection/authentication with the Android server.
         */
        protected void onPostExecute(Integer result) {
            t.interrupt();
            pd.dismiss();
            if (result == 1) {
                // Can't connect, tell user
                Toast.makeText(main.getApplicationContext(),
                        "No connection to the server.", Toast.LENGTH_LONG)
                        .show();
            } else if (result == 2) {
                // Can't authenticate, tell user
                Toast.makeText(main.getApplicationContext(),
                        "Login Failed. Incorrect username or password.",
                        Toast.LENGTH_LONG).show();
            } else if (result == 4) {
                // Can't login, tell user
                Toast.makeText(main.getApplicationContext(),
                        "Login Failed. Already logged in.", Toast.LENGTH_LONG)
                        .show();
            } else {
                // If linker has a valid connection
                if ((MainActivity.linker.authenticated() && MainActivity.linker
                        .connect())) {
                    Intent intent = new Intent(main, ChecklistActivity.class);
                    Bundle extras = new Bundle();
                    extras.putString("state", "START");
                    extras.putSerializable("nextActivity",
                            RouteMapTabActivity.class);
                    intent.putExtra("jtacck", extras);

                    // Check if GPS information has been updated yet
                    if (!MainActivity.hasUpdated) {
                        Location location = MainActivity.mLocManager
                                .getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
                        if (location != null) {
                            location = MainActivity.mLocManager
                                    .getLastKnownLocation(LocationManager.GPS_PROVIDER);
                            if (location != null) {
                                MainActivity.linker.updateGPS(
                                        location.getLatitude(),
                                        location.getLongitude());
                                MainActivity.hasUpdated = true;
                            }
                        }
                    }
                    main.startActivity(intent);
                }
            }
        }
    }

}
